#include "msgrouter.h"
#include "log.h"
#include "util.h"
#include "Game.h"
#include "def.h"
#include "context.h"

#include <csignal>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "action_http.h"

MainHandler::MainHandler() : HiveNS::Handler() {

}
MainHandler::~MainHandler(){

}

// from Handler
void MainHandler::onReceiveHttp(HiveNS::Http* pHttp){
    HttpData data;
    data.request_id = pHttp->getHandle();
    data.method = std::string(http_method_str((http_method)pHttp->getParser()->method));
    data.target = std::string(pHttp->getUrl(), pHttp->getUrlLength());
    data.body = std::string(pHttp->getBody(), pHttp->getBodyLength());
    CTools::get_remote_ip_and_port(pHttp->getSocketFD(), data.ip, data.port);
    g_Ctx.msg_router.ReceiveHttpData(data);
}

void MainHandler::onCurlResponse(HiveNS::Buffer* pBuffer, uint32 nodeID, uint32 callbackID, bool isRequestOK){
    CurlData data;
    data.callback_id = callbackID;
    data.body = std::string(pBuffer->data(), pBuffer->size());
    data.isOK = isRequestOK;
    g_Ctx.msg_router.ReceiveCurlData(data);
}

void MainHandler::onCloseHttp(HiveNS::Http* pHttp){

}

void MainHandler::onCloseListener(HiveNS::Listener* pListener){

}

// -----------
int MsgRouter::OnProcessMsg(MsgData&& msg_data)
{
	int cmd = msg_data.cmd;
	log_debug("cmd=0x%x", cmd);
	try
	{
        auto it = m_msg_handler.find(cmd);
        if (it == m_msg_handler.end())
        {
		    log_info("cmd not found:%d", cmd);
            return -1;
        }
        it->second(std::move(msg_data));
	}
	catch(const std::exception& e)
	{
		log_error("cmd=0x%x,error:%s", cmd, e.what());
	}
	catch(...)
	{
		log_error("cmd=0x%x, unknown exception", cmd);
	}
	
	return 0;
}

int MsgRouter::OnProcessTimer(int Timerid)
{
	try
	{
        auto it = m_timer_handler.find(Timerid);
        if (it == m_timer_handler.end())
        {
		    log_info("timer not found:%d", Timerid);
            return -1;
        }
        it->second(Timerid);
	}
	catch(const std::exception& e)
	{
		log_info("catch exception:%s", e.what());
	}
	catch(...)
	{
		log_info("catch unknown exception");
	}
	return 0;
}

void MsgRouter::EventHandle()
{
    int loopCnt = 10;
    for(int i=0;i<loopCnt;i++)
    {
        /*
        // --
        MsgData data;
        if (m_msgqueue.try_dequeue(data))
        {
            OnProcessMsg(std::move(data));
        }

        // --
        int timer_id = 0;
        if (m_timerqueue.try_dequeue(timer_id))
        {
            OnProcessTimer(timer_id);
        }
        */

        // --
        HttpData data2;
        if (m_rcvqueue.try_dequeue(data2))
        {
            OnGetMessage(std::move(data2));
        }
            
        // --
        CurlData data3;
        if (m_curlqueue.try_dequeue(data3))
        {
            OnCurlResponse(data3.callback_id, data3.body, data3.isOK);
        }
    }
        
}

void MsgRouter::ReceiveHttpData(HttpData& data){
    m_rcvqueue.enqueue(data);    
    SignalActiveEvent();
}
void MsgRouter::ReceiveCurlData(CurlData& data){
    m_curlqueue.enqueue(data);
    SignalActiveEvent();
}

bool MsgRouter::httpServerBack(uint32 request_id, int status_code,
    const std::map<std::string, std::string>& header_map, const std::string& body){
#ifdef TRACE_MODE
    log_error("request_id:%u,us:%lld", request_id, CTools::GetUnixTimeMs());
#endif
    HiveNS::MainWorker::getInstance()->sendBackToRequest(request_id, status_code, body, header_map);
#ifdef TRACE_MODE
    log_error("request_id:%u,us:%lld", request_id, CTools::GetUnixTimeMs());
#endif
    return true;
}


void MsgRouter::OnGetMessage(HttpData&& data){
    log_debug("request_id=%d method=%s target=%s body=%s", data.request_id, data.method.c_str(), data.target.c_str(), data.body.c_str());

    std::string type = CTools::ToUpStr(data.method);

    size_t index = data.target.find_first_of('?');
    if (index == std::string::npos)
    {
        data.fullpath = data.target;
    }
    else 
    {
        data.fullpath = data.target.substr(0, index);
        data.params = CTools::ParseUrlParams(data.target.substr(index + 1));
    }

    // 使用正则表达式, 传参使用vector<string>表示路径,方便查询
    try
    {
        bool bFound = false;
        CTools::split_str(data.fullpath.c_str(), "/", data.sub_paths);
        for (auto& item : m_http_svr_handle[type])
        {
            log_debug("path:%s,match:%s", data.fullpath.c_str(), item.first.c_str());
            if ((0 == data.fullpath.compare(item.first)) 
                || ((data.fullpath.size() > item.first.size()) && (data.fullpath[item.first.size()] == '/') && (0 == strncmp(item.first.c_str(), data.fullpath.c_str(), item.first.size()))))
            {
                item.second(std::move(data));
                bFound = true;
                break;
            }
        }
        if( !bFound){
            ActionHttp::HandleCommon(std::move(data));
        }
    }
    catch(const std::exception& e)
    {
        log_debug("catch exception:%s", e.what());
    }
    catch(...)
    {
        log_debug("catch unknown exception");
    }
}
// curl接收到返回结果
void MsgRouter::OnCurlResponse(uint32 callback_id, std::string& body, bool isOK){
    log_debug("OnCurlResponse callback_id=%u isOK=%d body=%s", callback_id, isOK, body.c_str());    
}

bool MsgRouter::sendHttpPOST(const std::string& url, const std::string& body, const std::map<std::string, std::string>& headers, uint32& callbackID)
{
    try
    {
        HiveNS::MainWorker::getInstance()->sendHttpPOST(url, body, headers, callbackID);
        return true;
    }
    catch(const std::exception& e)
    {
        log_debug("catch exception:%s", e.what());
    }
    catch(...)
    {
        log_debug("catch unknown exception");
    }
    return false;
}

bool MsgRouter::sendHttpGET(const std::string& url, const std::string& body, const std::map<std::string, std::string>& headers, uint32& callbackID)
{
    try
    {
        HiveNS::MainWorker::getInstance()->sendHttpGET(url, body, headers, callbackID);
        return true;
    }
    catch(const std::exception& e)
    {
        log_debug("catch exception:%s", e.what());
    }
    catch(...)
    {
        log_debug("catch unknown exception");
    }
    return false;
}

void MsgRouter::BindHttpHandle(std::string method, std::string target, std::function<void(HttpData&& data)> handle)
{
    m_http_svr_handle[CTools::ToUpStr(method)][target] = handle;
}

void MsgRouter::AddCurlEvent(std::int32_t event_id, std::function<void(std::string&, bool)> event_handle)
{
    //
}

MsgRouter::MsgRouter()
{    
    m_pActiveEvent = NULL;
}

MsgRouter::~MsgRouter()
{
    delete m_pActiveEvent;
    m_pActiveEvent = NULL;
}

bool MsgRouter::Init(int httpListenPort)
{
    log_debug(" called");
    // 创建httpserver线程
    MainHandler* pMainHandler = new MainHandler();
    pMainHandler->retain();
    log_debug(" MainHandler create");
    HiveNS::MainWorker::createInstance();
    HiveNS::MainWorker::getInstance()->setHandler(pMainHandler);
    HiveNS::MainWorker::getInstance()->setListenerAddress("0.0.0.0", httpListenPort);
    log_debug(" MainWorker startThread create");
    HiveNS::MainWorker::getInstance()->startThread();

    CreateActiveEvent();

    return true;
}

int MsgRouter::CreateActiveEvent(){
    if(m_pActiveEvent != NULL){
        return 0;
    }
	m_pActiveEvent = new CActiveEvent();

	int ret = m_pActiveEvent->create();
	if (0 != ret)
	{
		log_error("create CActiveEvent fail");
		return -1;
	}
	m_pActiveEvent->m_pServer = this;
	if (CCReactor::Instance()->AttachPoller(m_pActiveEvent) < 0)
	{
		log_error("attach poller fail");
		return -1;
	}
	return 0;
}

void MsgRouter::OnActiveEvent(){
    log_debug("OnActiveEvent called");
    EventHandle();
}

int MsgRouter::SignalActiveEvent(){
    return m_pActiveEvent->signal();
}






